package heap

import (
	"hi-jvm/classfile"
	"hi-jvm/instructions/base"
	"hi-jvm/rtda"
	"strings"
)

/*
类信息
 */
// name, superClassName and interfaceNames are all binary names(jvms8-4.2.1)
type Class struct {
	AccessFlags       uint16	// 访问标志
	Name              string // thisClassName
	SuperClassName    string
	InterfaceNames    []string
	ConstantPool      *ConstantPool	// 存放运行时常量池指针
	Fields            []*Field
	Methods           []*Method
	Loader            *ClassLoader
	SuperClass        *Class
	Interfaces        []*Class
	InstanceSlotCount uint
	StaticSlotCount   uint
	StaticVars        Slots
	InitStarted       bool	// 表示类初始化中，类的clInit方法是否已经发开始执行
}

/*
把class文件转换为Class结构体
 */
func newClass(cf *classfile.ClassFile) *Class {
	class := &Class{}
	class.AccessFlags = cf.AccessFlags
	class.Name = cf.ClassName()
	class.SuperClassName = cf.SuperClassName()
	class.InterfaceNames = cf.InterfaceNames()
	class.ConstantPool = newConstantPool(class, cf.Constantpool)
	class.Fields = newFields(class, cf.Fields)
	class.Methods = newMethods(class, cf.Methods)
	return class
}

func (self *Class)FindMethod(name, descriptor string) *Method {
	method := self.FindMethodFromClass(name, descriptor)
	if method == nil {
		method = self.FindMethodFromInterface(name, descriptor)
	}
	return method
}

func (self *Class)FindMethodFromClass(name, descriptor string) *Method {
	for c := self; c != nil; c = c.SuperClass {
		for _, method := range c.Methods {
			if method.Check(name, descriptor) {
				return method
			}
		}
	}
	return nil
}

func (self *Class)FindMethodFromInterface(name, descriptor string) *Method {
	for _, iface := range self.Interfaces {
		for _, method := range iface.Methods {
			if method.Check(name, descriptor) {
				return method
			}
		}

		method := iface.FindMethodFromInterface(name, descriptor)
		if method != nil {
			return method
		}
	}

	return nil
}

func (self *Class) NewObject() *Object {
	return newObject(self)
}

func (self *Class) IsPublic() bool {
	return isAccessEqual(self, ACC_PUBLIC)
}
func (self *Class) IsFinal() bool {
	return isAccessEqual(self, ACC_FINAL)
}
func (self *Class) IsSuper() bool {
	return isAccessEqual(self, ACC_SUPER)
}
func (self *Class) IsInterface() bool {
	return isAccessEqual(self, ACC_INTERFACE)
}
func (self *Class) IsAbstract() bool {
	return isAccessEqual(self, ACC_ABSTRACT)
}
func (self *Class) IsSynthetic() bool {
	return isAccessEqual(self, ACC_SYNTHETIC)
}
func (self *Class) IsAnnotation() bool {
	return isAccessEqual(self, ACC_ANNOTATION)
}
func (self *Class) IsEnum() bool {
	return isAccessEqual(self, ACC_ENUM)
}

/*
是否可以被类other访问
 */
// jvms 5.4.4
func (self *Class) isAccessibleTo(other *Class) bool {
	return self.IsPublic() ||
		self.GetPackageName() == other.GetPackageName()
}

func (self *Class) GetPackageName() string {
	if i := strings.LastIndex(self.Name, "/"); i >= 0 {
		return self.Name[:i]
	}
	return ""
}

func isAccessFlagEqual(accessFlag uint16, val uint16) bool {
	return 0 != accessFlag & val
}

func isAccessEqual(class* Class, val uint16) bool {
	return isAccessFlagEqual(class.AccessFlags, val)
}

func (self *Class) StartInit() {
	self.InitStarted = true
}

func (self *Class)InitClassIfNotInited(frame *rtda.Frame) bool {
	if self.InitStarted {
		return true
	}

	frame.RevertNextPC()
	base.InitClass(frame.Thread, self)
	return false
}

func (self *Class) GetClinitMethod() *Method {
	return self.getStaticMethod("<clinit>", "()V")
}

func (self *Class) getStaticMethod(name, descriptor string) *Method {
	for _, method := range self.Methods {
		if method.IsStatic() &&
			method.Name == name &&
			method.Descriptor == descriptor {
			return method
		}
	}
	return nil
}


func (self *Class) ArrayClass() *Class {
	arrayClassName := getArrayClassName(self.Name)
	return self.Loader.LoadClass(arrayClassName)
}

